package com.qf.automation.user.controller;

import com.alibaba.fastjson.JSONObject;
import com.qf.automation.user.client.FaceClient;
import com.qf.automation.user.client.FileClient;
import com.qf.automation.user.client.SMSClient;
import com.qf.automation.user.dto.*;
import com.qf.automation.user.model.User;
import com.qf.automation.user.service.UserService;
import com.qf.automation.user.vo.SignInVO;
import com.qf.base.controller.BaseController;
import com.qf.base.face.dto.FaceDTO;
import com.qf.base.file.QRCodeFTO;
import com.qf.base.pojo.UserVO;
import com.qf.base.result.R;
import com.qf.base.sms.dto.SendSMSDTO;
import com.qf.base.utils.FileBase64Util;
import com.qf.base.utils.PropertiesUtil;
import freemarker.template.utility.StringUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.text.DateFormat;
import java.util.*;

//用户登陆注册问题
@RestController
@RequestMapping("/user")
public class UserController extends BaseController {
    @Resource
    private UserService userService;
    @Resource
    private SMSClient smsClient;
    @Resource
    private FileClient fileClient;
    @Resource
    private FaceClient faceClient;
    private static int  TOKEN_EXPIRE=1000*60*30;
    private static String TOKEN_KEY="qf";
//登陆
    @PostMapping("/signin")
    @CrossOrigin  //ajax 跨域的注解
    public R signIn(@RequestBody SignInDto signInDto){
        String signName = signInDto.getSignName();
        String password = signInDto.getPassword();
//        查找用户是否存在
        User user = userService.signIn(signName, password);
//        返回的对象被忽略的方式
        SignInVO signInVO=new SignInVO();
        if (user!=null){
            PropertiesUtil.copy(user,signInVO);
            //使用JWT发送token  返回token
            String s = generatorToken(signName, JSONObject.toJSONString(signInVO));
            System.out.println(s);
            JSONObject result=new JSONObject();
            result.put("token", s);
            result.put("user",user);
//            System.out.println(result.getString("token"));
            for (int i=0;i<1;i++){
                continue;
            }
            return R.ok(result);
        }else {
            return R.error(501,"登陆信息有误");
        }
    }


    //生成token
    private static String generatorToken(String nickname, Object user){
        //JWT 构成   分三部分   每一个部分都是字符串
//                第一部分   Header  内部包含算法方式token类型信息
//                第二部分   携带信息部分   我们可以把一个User对象放到json放到第二部分中，放入后是加密的信息，折后任何一个服务都可以拿到这个json进而知道用户的id是扫描（解密）
//                第三部分   字符串  是第一部分和第二部分拼接起来   进行HS256加密 然后再做base64url加密
        String token = Jwts.builder()
//               设置用户昵称
                .setSubject(nickname)
//               设置tikon时间
                .setIssuedAt(new Date())
//               设置token过期时间
                .setExpiration(new Date(System.currentTimeMillis() + TOKEN_EXPIRE))
//               设置携带的对象
                .claim("user", user)
//               设置加密方式，以及密钥
                .signWith(SignatureAlgorithm.HS256, TOKEN_KEY.getBytes())
//               生成token
                .compact();
        return token;
    }


    //根据token解析token获得对象，如果没获得就是过期或者错误
    @GetMapping("/token")
    public R token(){
//        String token = jsonObject.getString("token");
//        String value = checkToken(token).toString();
        UserVO user = user();
        if (user==null){
//            token不对劲，重新登陆
            return R.error(500,"用户身份有误，重新登陆");
        }else {
//            token一切正常，返回用户的信息
            return R.ok(200,"校验身份成功").setResult(user);
        }

    }
    //解析token
    private R checkToken(String token){
        Claims body=null;
        try {
           body =Jwts.parser().setSigningKey(TOKEN_KEY.getBytes())
                    .parseClaimsJws(token).getBody();
        }catch (Exception e){
//            e.printStackTrace();
            return R.error(501,"无效的token。");
        }
        Object user = body.get("user");
        //举例说明，以map1为例子
        //map1.put("a",map2);  这是我们希望的
        //map1.put("a",JSONObject.toJSONString(map2));  这是我们需要避免的。

        //类比到jsonobject里：
        //jsonobject1.put("a",jsonobject2);  这是我们希望的
        //jsonobject1.put("a",jsonobject2.toJSONString());  这是我们应该避免的。
        return R.ok(JSONObject.parse(user.toString()));
    }



    //热加载校验用户名是否是电话号
    @PostMapping("/check/telephone")
    public R checkTelephone(@RequestBody JSONObject telephoneObject){
        String phoneNo = telephoneObject.getString("userInfo");
        boolean result = userService.checkUserInfo(phoneNo, 1);
        if (result){
            return R.ok(201,"手机号已存在");
        }else {
            return R.ok(200,"手机号可以使用");
        }
    }

    @PostMapping("/check/email")
    public R checkMail(@RequestBody JSONObject emailObject){
        String email = emailObject.getString("userInfo");
        boolean result = userService.checkUserInfo(email, 2);
        if (result){
            return R.ok(201,"邮箱已存在");
        }else {
            return R.ok(200,"邮箱可以使用");
        }
    }
    //可以不填写，不填写就用默认的用户名
    @PostMapping("/check/username")
    public R checkUsername(@RequestBody JSONObject userObject){
//


        String user = userObject.getString("userInfo");
        boolean result = userService.checkUserInfo(user, 3);
        if (result){
            return R.ok(201,"用户已存在");
        }else {
            return R.ok(200,"用户可以使用");
        }
    }




    /**
     * 发送短信
     */
    @PostMapping("/sms")
    public R sendSMS(@RequestBody SMSDTO smsdto){

        String telephoneNo = smsdto.getTelephoneNo();
        //子服务调用，返回的对象
        SendSMSDTO sendSMSDTO=new SendSMSDTO();
        sendSMSDTO.setPhoneNo(telephoneNo);
        //六位验证码拼接
        Random random = new Random();
        String code =""+random.nextInt(10)
                +random.nextInt(10)
                +random.nextInt(10)
                +random.nextInt(10)
                +random.nextInt(10)
                +random.nextInt(10);
        sendSMSDTO.setCode(code);
        String smsResult = smsClient.postSMS(sendSMSDTO);
        JSONObject smsObject=JSONObject.parseObject(smsResult);
        System.out.println();
        if (smsObject.getInteger("code")==200){
            return R.ok(200,"调用短信验证码已经发送");

        }else {
            return R.error(501,"发送短信失败");
        }
    }



//注册提交  校验短信是否正确    电话短信响应的短信是否存在
    @PostMapping("/signup")
    public R signUp(@RequestBody SignUpDTO signUpDTO){
        User user=new User();
        PropertiesUtil.copy(signUpDTO,user);
        //1、输入的短信验证码是否正确
        //调用短信平台服务，输入用户输入的验证码，比对。
        SendSMSDTO sendSMSDTO=new SendSMSDTO();
        sendSMSDTO.setPhoneNo(signUpDTO.getTelephone());
        sendSMSDTO.setCode(signUpDTO.getSms());
        //
        String smsResult = smsClient.checkSMS(sendSMSDTO);
        int code = JSONObject.parseObject(smsResult).getInteger("code");
        if (code==200){
            int result = userService.signUp(user);
            if(result==0){
                return R.error(500,"注册失败");
            }else{
                return R.ok(200,"注册成功");
            }
        }else if(code==501){
            return R.error(501,"验证码错误");
        }else if(code==502){
            return R.error(502,"验证码已经失效");
        }else{
            return R.error(503,"短信中心未知异常");
        }
    }


    /**
     * 手机号一键登录
     */
    @PostMapping("/mobilesignin")
    public R mobileSignIn(@RequestBody MobileSignInDTO mobileSignInDTO){
        String phoneNo=mobileSignInDTO.getPhoneNo();
        String sms = mobileSignInDTO.getSms();
        //验证手机号短信验证码是否正确且有效
        SendSMSDTO sendSMSDTO=new SendSMSDTO();
        sendSMSDTO.setCode(sms);
        sendSMSDTO.setPhoneNo(phoneNo);
        String s = smsClient.checkSMS(sendSMSDTO);
        int code=JSONObject.parseObject(s).getInteger("code");
        if (code==200){
            //短信验证成功
            // 应该让这个用户登陆
            //  发送token
            //应该根据手机号返回true
            //如果手机号查不到user
            User user=userService.returnUserByPhoneNo(phoneNo);
            SignInVO signInVO=new SignInVO();
            PropertiesUtil.copy(user,signInVO);
            String token=generatorToken(user.getNickname(),JSONObject.toJSONString(signInVO));
            JSONObject tokenResult=new JSONObject();
            tokenResult.put("token", token);
            return R.ok(200,"登陆成功").setResult(tokenResult);
        }else if (code==501){
            return R.error(501,"验证码错误");
        } else if (code==502){
            return R.error(502,"短信时间超时");
        } else {
            return R.error(500,"未知异常");
        }

    }
    @Transactional
    //测试token续签
    @PostMapping("/header")
    public R getHeader(@RequestBody MobileSignInDTO mobileSignInDTO){
        return R.ok(200,"获取userid").setResult(userId());
    }

    /**
     * 上传头像功能
     * 现在仅仅事上传文件
     * 后期我们需要将-------------------------------------------------------
     * @param iconDTO
     * @return
     */
    @PostMapping("/icon")
    public R uploadIcon(@RequestBody IconDTO iconDTO){
        String fileResult= fileClient.saveImage(iconDTO);
        if (200==JSONObject.parseObject(fileResult).getInteger("code")){
            String url=JSONObject.parseObject(fileResult).getString("result");
            int result = userService.saveIcon(userId(), url);
            if (result>0){
                return R.ok(200,"上传成功");
            }else {
                return R.error(500,"上传失败");
            }
        }
        return R.error(500,"上传失败");


    }
    /**
     * 人脸登陆的接口
     * 调用人脸子服务，根据用户照片获取人脸对应的id
     */
    @PostMapping("/face")
    public R facesignIn(@RequestBody FaceSignInDTO faceSignInDTO){
        String base64=faceSignInDTO.getBase64();
        //调用自服务
        FaceDTO faceDTO=new FaceDTO();
        faceDTO.setUserId(null);
        faceDTO.setBase64(base64);
        String result = faceClient.searchFace(faceDTO);
        Integer code = JSONObject.parseObject(result).getInteger("code");
        if (code!=200){
            return R.error(500,"登陆失败");
        }
        Long userId = JSONObject.parseObject(result).getLong("result");
        //根据
        User user=userService.findUserById(userId);
        //筛选返回参数
        SignInVO signInVO=new SignInVO();
        String s = generatorToken(user.getNickname(), JSONObject.toJSONString(signInVO));
        System.out.println(s);
        JSONObject r=new JSONObject();
        r.put("token", s);
        r.put("user",user);
//            System.out.println(result.getString("token"));
        return R.ok(r);



    }
    /**
     * 批量查看用户的接口
     * 这个接口传入一组uid，返回一组user
     * 展示好友列表等功能，就可以用这个额接口
     */
    @PostMapping("/batch")
    public R batchFindUser(@RequestBody Map<String,Object> param){
        ArrayList userIds= (ArrayList) param.get("userIds");
        List<SignInVO> signInVOS=new ArrayList<>();
        //根据一组userId
        //查询一组user
        List<User> users = userService.findUsersByIds(userIds);
        //转化
        for (int i = 0; i < users.size(); i++) {
            SignInVO signInVO=new SignInVO();
            PropertiesUtil.copy(users.get(i),signInVO);
            signInVOS.add(signInVO);
        }
        return R.ok(signInVOS);
    }
    @GetMapping("/qrcode")
    public R showMyQRCode(){

        Long userId = userId();
        User user=userService.findUserById(userId);
        SignInVO signInVO=new SignInVO();
        PropertiesUtil.copy(user,signInVO);
        String jsonString=JSONObject.toJSONString(signInVO);
        QRCodeFTO qrCodeFTO=new QRCodeFTO();
        qrCodeFTO.setContent(jsonString);
        String fileResult = fileClient.getQRC(qrCodeFTO);
        String base64 = JSONObject.parseObject(fileResult).getString("result");
        return R.ok(200,"生成成功").setResult(base64);
    }
}
